/*
*  Copyright (C) 2009  Peter Kist & Jan Ripke
*
*  This program is free software: you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation, either version 3 of the License, or
*  (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/


#include <boost/test/unit_test.hpp>

#include <vector>

#include <mediator/InterMediator.h>
#include <mediator/Consumer.h>
#include <mediator/Producer.h>
#include <mediator/Event.h>
#include <mediator/Request.h>

//#include <mediator/ModuleIdentifier.h>
//#include <mediator/Mediator.h>
//#include <mediator/Producer.h>
//#include <mediator/Consumer.h>
//#include <mediator/Event.h>

//#include <mediator/Interface.h>

using namespace galaxy::mediator;
using namespace std;


BOOST_AUTO_TEST_SUITE( test_suite_mediator )

class GfxConsumer: public Consumer {
public:
    int c;
    GfxConsumer () { c = 0; };
    virtual ~GfxConsumer () { };
    virtual const char * consumerType () { return "GfxConsumer"; };
    virtual void handleEvent (Event& event) { c++; };
};
class InputConsumer: public Consumer {
public:
    int c;
    InputConsumer () { c = 0; };
    virtual ~InputConsumer () { };
    virtual const char * consumerType () { return "InputConsumer"; };
    virtual void handleEvent (Event& event) { c++; };
};
class LogicProducer: public Producer {
public:
    int c;
    LogicProducer () { c = 0; };
    virtual ~LogicProducer() { };
    virtual int category () { return (int) CATEGORY_LOGIC; };
    virtual bool handleRequest(const Request &Request, RequestResultPtr& result) { c++; return true;};
};
class TestEvent: public Event {
public:
    int c;
    TestEvent () { };
    TestEvent (TestEvent& e) : Event (e) { };
    TestEvent (int val) : Event (CATEGORY_DEBUG, Identifier::any, Identifier::any) { c = val; };
    virtual Event * clone () { return new TestEvent(*this); };
};

class intermediator_fixture {
public:
    GfxConsumer      gfxConsumer;
    InputConsumer    inputConsumer;
    LogicProducer    logicProducer;
    RequestResultPtr   result;
    TestEvent      * event;

    intermediator_fixture () {
        InterMediator::initialize ();

        InterMediator::registerProducer(logicProducer);

        InterMediator::registerConsumer(gfxConsumer);
        InterMediator::registerConsumer(inputConsumer);
        InterMediator::registerInterest(gfxConsumer.consumerType(),Identifier(CATEGORY_GFX,1,Identifier::any));
        InterMediator::registerInterest(gfxConsumer.consumerType(),Identifier(CATEGORY_GFX,2,1));
        InterMediator::registerInterest(gfxConsumer.consumerType(),Identifier(CATEGORY_GFX,2,Identifier::any));
        InterMediator::registerInterest(inputConsumer.consumerType(),Identifier(CATEGORY_INPUT,1,1));
    };
    virtual ~intermediator_fixture () {
        InterMediator::terminate();
    };
};

BOOST_FIXTURE_TEST_CASE(InterMediator, intermediator_fixture) {

    BOOST_CHECK (galaxy::mediator::InterMediator::postEvent(Event(CATEGORY_INPUT, 1, 1), POST_IMMEDIATE));
    BOOST_CHECK_EQUAL (gfxConsumer.c, 0);
    BOOST_CHECK_EQUAL (inputConsumer.c, 1);

    gfxConsumer.c = 0;
    inputConsumer.c = 0;
    BOOST_CHECK (galaxy::mediator::InterMediator::postEvent(Event(CATEGORY_GFX, 2, 1), POST_IMMEDIATE));
    BOOST_CHECK_EQUAL (gfxConsumer.c, 2);
    BOOST_CHECK_EQUAL (inputConsumer.c, 0);

    gfxConsumer.c = 0;
    inputConsumer.c = 0;
    BOOST_CHECK (galaxy::mediator::InterMediator::postEvent(Event(CATEGORY_GFX, 2, 2), POST_IMMEDIATE));
    BOOST_CHECK_EQUAL (gfxConsumer.c, 1);
    BOOST_CHECK_EQUAL (inputConsumer.c, 0);

    galaxy::mediator::InterMediator::RequestProducer (Request(CATEGORY_LOGIC, 1, 1), result);
    BOOST_CHECK_EQUAL (logicProducer.c, 1);

    gfxConsumer.c = 0;
    BOOST_CHECK (galaxy::mediator::InterMediator::postEvent(Event(CATEGORY_GFX, 2, 2), POST_DELAYED));
    BOOST_CHECK (galaxy::mediator::InterMediator::postEvent(Event(CATEGORY_GFX, 2, 2), POST_DELAYED));
    BOOST_CHECK_EQUAL (gfxConsumer.c, 0);

    BOOST_CHECK (gfxConsumer.hasEvents());
    gfxConsumer.popEvent((Event *&) event);
    BOOST_CHECK (event);
    gfxConsumer.terminateEvent (event);
    BOOST_CHECK (gfxConsumer.hasEvents());
    gfxConsumer.popEvent((Event *&) event);
    BOOST_CHECK (event);
    BOOST_CHECK_EQUAL (gfxConsumer.hasEvents(), false);
    gfxConsumer.terminateEvent (event);

}

/*
struct fixture1 {
ModuleIdentifier consumer1;
ModuleIdentifier consumer2;
ModuleIdentifier consumer3;

fixture1() {
consumer1 = ModuleIdentifier(MODULE_CATEGORY_INPUT,2,3);
consumer2 = ModuleIdentifier(MODULE_CATEGORY_INPUT,ModuleIdentifier::match_any,ModuleIdentifier::match_any);
consumer3 = ModuleIdentifier(MODULE_CATEGORY_AUDIO,2,ModuleIdentifier::match_any);
};
~fixture1() { };

};

BOOST_FIXTURE_TEST_CASE(ModuleIdentifierTest, fixture1) {

// simulate 3 consumer id's
BOOST_CHECK_EQUAL (consumer1.matches(ModuleIdentifier(MODULE_CATEGORY_INPUT,2,3)), 3);
BOOST_CHECK_EQUAL (consumer1.matches(ModuleIdentifier(MODULE_CATEGORY_INPUT,2,2)), ModuleIdentifier::no_match);

BOOST_CHECK_EQUAL (consumer2.matches(ModuleIdentifier(MODULE_CATEGORY_INPUT,2,2)), 1);
BOOST_CHECK_EQUAL (consumer2.matches(ModuleIdentifier(MODULE_CATEGORY_AUDIO,2,2)), ModuleIdentifier::no_match);

BOOST_CHECK_EQUAL (consumer3.matches(ModuleIdentifier(MODULE_CATEGORY_AUDIO,2,2)), 2);
BOOST_CHECK_EQUAL (consumer3.matches(ModuleIdentifier(MODULE_CATEGORY_AUDIO,1,2)), ModuleIdentifier::no_match);
BOOST_CHECK_EQUAL (consumer3.matches(ModuleIdentifier(MODULE_CATEGORY_INPUT,1,2)), ModuleIdentifier::no_match);

}


class TestProducer: public Producer {
public:
int count;
TestProducer() { count = 0; };
virtual ~TestProducer() { };
virtual bool handleRequest(const Request& Request, RequestResultPtr& result) { count++; return true; };
};

class TestConsumer: public Consumer {
public:
int count;
TestConsumer() { count = 0; };
virtual ~TestConsumer() { };
void handleEvent(Event& event) {
count++;
}
};


struct fixture2 {
Mediator          mediator;
TestProducer      producer1;
TestConsumer      consumer1;
TestConsumer      consumer2;
TestConsumer      consumer3;
TestConsumer      consumer4;
vector<Consumer*> consumers;

fixture2() {
mediator.registerProducer(producer1, MODULE_CATEGORY_INPUT);
mediator.registerConsumer(consumer1, ModuleIdentifier(MODULE_CATEGORY_INPUT,2,3));
mediator.registerConsumer(consumer2, ModuleIdentifier(MODULE_CATEGORY_INPUT,2,ModuleIdentifier::match_any));
mediator.registerConsumer(consumer2, ModuleIdentifier(MODULE_CATEGORY_INPUT,1,ModuleIdentifier::match_any));
mediator.registerConsumer(consumer2, ModuleIdentifier(MODULE_CATEGORY_INPUT,4,ModuleIdentifier::match_any));
mediator.registerConsumer(consumer3, ModuleIdentifier(MODULE_CATEGORY_MUSIC,ModuleIdentifier::match_any, ModuleIdentifier::match_any));
}
~fixture2() {
consumers.clear();
};
};

BOOST_FIXTURE_TEST_CASE(MediatorTest, fixture2) {

// check registered producer and consumers
BOOST_CHECK ( mediator.findProducer(MODULE_CATEGORY_INPUT) );
BOOST_CHECK ( mediator.findConsumers(consumers, ModuleIdentifier(MODULE_CATEGORY_INPUT,2,3))); 
BOOST_CHECK_EQUAL ( consumers.size(), 2 ); // finds consumer 1 and 2 (1,2,*)
BOOST_CHECK ( mediator.findConsumers(consumers, ModuleIdentifier(MODULE_CATEGORY_INPUT,1,1))); 
BOOST_CHECK_EQUAL ( consumers.size(), 1 ); // finds consumer 2 (1,1,*)
BOOST_CHECK ( mediator.findConsumers(consumers, ModuleIdentifier(MODULE_CATEGORY_MUSIC,3,3))); 
BOOST_CHECK_EQUAL ( consumers.size(), 1 ); // finds consumer 3 (3,3,3)
BOOST_CHECK ( mediator.findConsumers(consumers, ModuleIdentifier(MODULE_CATEGORY_INPUT,4,1))); 
BOOST_CHECK_EQUAL ( consumers.size(), 1 ); // finds consumer 4 (1,4,*)

mediator.initialize ();

mediator.postEvent(Event(MODULE_CATEGORY_INPUT,2,3)); // calls consumer 1 and 2
mediator.postEvent(Event(MODULE_CATEGORY_INPUT,2,4)); // calls consumer 2
mediator.postEvent(Event(MODULE_CATEGORY_INPUT,1,1)); // calls consumer 2
mediator.postEvent(Event(MODULE_CATEGORY_INPUT,4,ModuleIdentifier::match_any), Mediator::byCaller); // calls consumer 4
mediator.postEvent(Event(MODULE_CATEGORY_MUSIC,1,1)); // calls consumer 3
while (mediator.queueEmpty() == false) {
boost::this_thread::yield();
}

BOOST_CHECK_EQUAL (consumer1.count, 1);
BOOST_CHECK_EQUAL (consumer2.count, 3);
BOOST_CHECK_EQUAL (consumer3.count, 1);
BOOST_CHECK_EQUAL (consumer4.count, 1);

RequestResultPtr result;
mediator.RequestProducer(Request(MODULE_CATEGORY_INPUT, 1, 1), result);
BOOST_CHECK_EQUAL (producer1.count, 1);
}
*/
BOOST_AUTO_TEST_SUITE_END()
